/*
 * Robust Pointers - A framework for robust pointers in a MT environment.
 * http://code.google.com/p/rptr/
 *
 * Copyright (c) 2009, Bill K. Barekas <bbarekas@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *    1. Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *    3. Neither the name of the author nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file    rptr_impl.h
 * @author  Bill K. Barekas <bbarekas@gmail.com>
 * @date    October 4, 2009
 * @version $Id$
 *
 * This file contains the declarations for the internal data structures
 * of the Robust PoinTeR library.
 */


#ifndef RPRT_IMPL_H_
#define RPRT_IMPL_H_


#include <stdint.h>
#include <pthread.h>
#include "bsdqueue.h"

#include "rptr.h"


/*
 * Forward declarations.
 */
typedef struct rptr_global_s            rptr_global;
typedef struct rptr_type_i_s            rptr_type_i;
typedef struct rptr_i_s                 rptr_i;

TAILQ_HEAD(rptr_qh, rptr_i_s);


/*
 * Macros
 */
#define LOG_MUTEX                 //printf
#define LOG_ERROR                 printf


/* RPTR_GLOBAL_LOCK */
#define RPTR_GLOBAL_LOCK()                                                  \
do {                                                                        \
  LOG_MUTEX("RPTR_GLOBAL LOCK @ %s:%d\n", __FILE__, __LINE__);              \
  if ((pthread_mutex_lock(&rptr_data.lock)) != 0) {                         \
    LOG_ERROR("pthread_mutex_lock failed.\n");                              \
  }                                                                         \
  else {                                                                    \
    LOG_MUTEX("RPTR_GLOBAL LOCK @ %s:%d OK!\n", __FILE__, __LINE__);        \
  }                                                                         \
} while(0)


/* RPTR_GLOBAL_UNLOCK */
#define RPTR_GLOBAL_UNLOCK()                                                \
do {                                                                        \
  LOG_MUTEX("RPTR_GLOBAL UNLOCK @ %s:%d !!!\n", __FILE__, __LINE__);        \
  if ((pthread_mutex_unlock(&rptr_data.lock)) != 0) {                       \
    LOG_ERROR("pthread_mutex_lock failed.\n");                              \
  }                                                                         \
} while(0)


/* RPTR_OBJ_LOCK */
#define RPTR_OBJ_LOCK(obj)                                                      \
do {                                                                        \
  LOG_MUTEX("RPTR:%d LOCK @ %s:%d\n", (obj)->u.id, __FILE__, __LINE__);     \
  if ((pthread_mutex_lock(&(obj)->lock)) != 0) {                            \
    LOG_ERROR("pthread_mutex_lock failed.\n");                              \
  }                                                                         \
  else {                                                                    \
    LOG_MUTEX("RPTR:%d LOCK @ %s:%d OK!\n", (obj)->u.id, __FILE__, __LINE__); \
  }                                                                         \
} while(0)


/* RPTR_OBJ_UNLOCK */
#define RPTR_OBJ_UNLOCK(obj)                                                    \
do {                                                                        \
  LOG_MUTEX("RPTR:%d UNLOCK @ %s:%d !!!\n", (obj)->u.id, __FILE__, __LINE__); \
  if ((pthread_mutex_unlock(&(obj)->lock)) != 0) {                          \
    LOG_ERROR("pthread_mutex_lock failed.\n");                              \
  }                                                                         \
} while(0)


/**
 * rptr_global structure.
 *
 * This structure represents ...
 */
struct rptr_global_s {
  pthread_mutex_t            lock;               /** Mutex lock to protect internal structure fields. */
  struct rptr_qh             free_queue;         /** Queue of free objects. */
  volatile uint32_t          free_objs;          /** Number of free objects in free_list. */
  volatile uint32_t          num_types;          /** Number of types registered. */
  volatile uint32_t          type_ids;           /** Type id counter. */
  rptr_type_i *              types;              /** Array for registered types. */
  volatile uint32_t          num_objs;           /** Global number of objects totally created. */
  volatile uint32_t          num_objs_active;    /** Global number of objects currently active. */
  volatile uint32_t          num_objs_freed;     /** Global number of objects freed. */
  volatile uint32_t          bytes_allocated;    /** Global number of bytes allocated. */
  volatile uint32_t          bytes_net_allocated;/** Net number of bytes allocated. */
  uint32_t                   init_objs;          /** Number of objs to start with. */
  uint32_t                   inc_step_objs;      /** Number of objs to add when full. */
  uint32_t                   low_watermark;      /** Watermark to indicate low use. */
  uint32_t                   high_watermark;     /** Watermark to indicate high use. */
  uint32_t                   reuse_period;       /** Interval after that the objs can be reused. */
  uint32_t                   initialized;        /** Initialize flag. */
};


/**
 * rptr_type structure.
 *
 * This structure represents ...
 */
struct rptr_type_i_s {
  uint32_t                   id;                 /** Unique type id. */
  uint32_t                   index;              /** Entry index. */
  char *                     full_name;          /** Full name for type. */
  char *                     abbr_name;          /** Name used for logging. */
  uint32_t                   size;               /** Object size. */
  volatile uint32_t          num_objs;           /** Number of objects totally created. */
  volatile uint32_t          num_objs_active;    /** Number of objects currently active. */
  volatile uint32_t          num_objs_freed;     /** Number of objects freed. */
};


/**
 * rptr_status enum.
 *
 * This enumerates all the status for a auto_ptr_i structure.
 */
enum rptr_status_e {
  RPTR_FREE,
  RPTR_ALLOCATED
};
typedef enum rptr_status_e    rptr_status;


/**
 * rptr_i structure.
 *
 * This structure represents ...
 */
struct rptr_i_s {
  TAILQ_ENTRY(rptr_i_s)      queue_entry;        /** Queue entry for free_list. */

  rptr_status                status;             /** Object status. */
  time_t                     tstamp;             /** Object timestamp. */
  pthread_mutex_t            lock;               /** Mutex lock to protect internal structure fields. */
  void *                     ptr;                /** Pointer to the actual object. */
  union {
    struct {
      uint32_t                  id;
      uint8_t                   type;
      uint8_t                   status;
    } u;
    uint64_t                    oid;
  };
};


#endif /* RPRT_IMPL_H_ */
